package com.lipaluma.field.mapper.single.impl;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;

import com.lipaluma.annotations.validations.ValidateDate;
import com.lipaluma.context.Context;
import com.lipaluma.exceptions.CsvParserProcessException;
import com.lipaluma.field.mapper.mapping.MappingInfo;
import com.lipaluma.field.mapper.mapping.MappingOptions;
import com.lipaluma.field.mapper.single.AbstractStandardSingleFieldMapper;
import com.lipaluma.field.validator.ChainValidator;
import com.lipaluma.field.validator.ValidationBasicOptions;
import com.lipaluma.field.validator.ValidatorFactory;
import com.lipaluma.util.ParserUtils;
import com.lipaluma.xml.mapping.XmlFieldMapping;
/**
 * Field Mapper used to map a date by {@link Date} or {@link DateTime}
 * 
 * @author Mario
 */
public class DateTimeFieldMapper extends AbstractStandardSingleFieldMapper {
	public static final String DEFAULT_PATTERN = "yyyy-MM-dd";
	private String pattern;
	
	public DateTimeFieldMapper() {}
	/**
	 * Field Mapper used to map a Date.<br/>
	 * The default pattern for the date is 'yyyy-MM-dd'
	 * @param mapping information of mapping
	 */
	public DateTimeFieldMapper(MappingInfo mapping) {
		super(mapping);
	}
	/**
	 * Field Mapper used to map a Date with the given pattern for the date.
	 * @param columnIndex index of the MapColumn
	 * @param pattern pattern of the date
	 */
	public DateTimeFieldMapper(MappingInfo mapping, String pattern) {
		super(mapping);
		this.pattern = pattern;
	}
	
	@Override
	protected void init(MappingOptions mappingOptions) {
		pattern = mappingOptions.getPattern();
	}
	
	@Override
	public ChainValidator createChainValidator(Context context, Field field) {
		ValidationBasicOptions validationOptions = ValidationBasicOptions.builder().byAnnotation(field.getAnnotation(ValidateDate.class)).build();
		return ValidatorFactory.createNewChainValidator(context, field, validationOptions);
	}

	@Override
	public ChainValidator createChainValidator(Context context, Field field, XmlFieldMapping mapping) {
		return ValidatorFactory.createNewChainValidator(context, field, mapping);
	}

	@Override
	protected Object parseExtractedValue(String value) {
		String pattern = StringUtils.isNotBlank(this.pattern)? this.pattern : DEFAULT_PATTERN;
		try {
			return ParserUtils.parseToType(field.getType(), value, pattern);
		} catch (Exception e) {
			throw new CsvParserProcessException(this, "The value "+value+" can't be parsed to a date by the pattern "+pattern, e);
		}
	}
	
	@Override
	protected String formatValueToWriteOnRow(Object value) {
		String pattern = StringUtils.isNotBlank(this.pattern)? this.pattern : DEFAULT_PATTERN;
		if(Date.class.isAssignableFrom(value.getClass())) {
			SimpleDateFormat sdf = new SimpleDateFormat(pattern);
			return sdf.format((Date)value);
		} else if(DateTime.class.isAssignableFrom(value.getClass())) {
			return ((DateTime)value).toString(pattern);
		} else
			return value.toString();
	}
}
